/**
 * 
 */
package com.gragra.sampling.sequentialStructure;
import java.util.Arrays;
import java.util.HashSet;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap.Entry;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
/**
 * on infinite information levels -1 is used to indicate absence, otherwise
 * null indicates absence
 * @author Christoph Teichmann
 * created Mar 24, 2013 11:09:31 AM
 * @version 0.1
 */
public class ExtensionInformationHolder
{
	/**
	 * 
	 */
	private final Object2ObjectOpenHashMap<ExtensionInformationLevel, ExtensionInformationValue>[] finiteData;
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		StringBuilder builder = new StringBuilder();
		builder.append("ExtensionInformationHolder [finiteData=");
		builder.append(Arrays.toString(finiteData));
		builder.append(", infiniteData=");
		builder.append(Arrays.toString(infiniteData));
		builder.append("]");
		return builder.toString();
	}
	/**
	 * 
	 */
	private final Object2IntOpenHashMap<ExtensionInformationLevel>[] infiniteData;
	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	public ExtensionInformationHolder(int size)
	{
		finiteData = new Object2ObjectOpenHashMap[size];
		infiniteData = new Object2IntOpenHashMap[size];
		for(int i=0;i<size;++i)
		{
			finiteData[i] = new Object2ObjectOpenHashMap<ExtensionInformationLevel, ExtensionInformationValue>();
			infiniteData[i] = new Object2IntOpenHashMap<ExtensionInformationLevel>();
			infiniteData[i].defaultReturnValue(-1);
		}
	}
	/**
	 * 
	 *
	 * @param position
	 * @param eil
	 * @param eiv
	 * @return
	 */
	public ExtensionInformationValue addInformation(int position, ExtensionInformationLevel eil, ExtensionInformationValue eiv)
	{return this.finiteData[position].put(eil, eiv);}
	/**
	 * 
	 *
	 * @param position
	 * @param eil
	 * @return
	 */
	public ExtensionInformationValue getFiniteInformation(int position, ExtensionInformationLevel eil)
	{return this.finiteData[position].get(eil);}
	/**
	 * 
	 *
	 * @param position
	 * @param eil
	 * @return
	 */
	public int getInfiniteInformation(int position, ExtensionInformationLevel eil)
	{return this.infiniteData[position].getInt(eil);}
	/**
	 *
	 * @param pos
	 * @param el
	 * @param value
	 */
	public void addInformation(int pos, ExtensionInformationLevel el, int value)
	{this.infiniteData[pos].put(el, value);}
	/**
	 * returns a string representation for the information at the given position, in the form
	 * (|ExtensionLevel|Value)*
	 *  
	 * @param i
	 * @return
	 */
	public String getCombinedString(int position)
	{
		StringBuilder sb = new StringBuilder();
		Object2ObjectOpenHashMap<ExtensionInformationLevel, ExtensionInformationValue> map1 = this.finiteData[position];
		for(Entry<ExtensionInformationLevel, ExtensionInformationValue> ent : map1.object2ObjectEntrySet())
		{
			sb.append("|");
			sb.append(ent.getKey().toString());
			sb.append("|");
			sb.append(ent.getValue().toString());
		}
		Object2IntOpenHashMap<ExtensionInformationLevel> map2 = this.infiniteData[position];
		for(it.unimi.dsi.fastutil.objects.Object2IntMap.Entry<ExtensionInformationLevel> ent : map2.object2IntEntrySet())
		{
			sb.append("|");
			sb.append(ent.getKey().toString());
			sb.append("|");
			sb.append(ent.getValue().toString());
		}
		return sb.toString();
	}
	/**
	 * 
	 * @param i
	 * @return
	 */
	public Object2ObjectOpenHashMap<ExtensionInformationLevel, ExtensionInformationValue> getFiniteInformationAt(int pos)
	{return this.finiteData[pos];}
	/**
	 * 
	 * @param pos
	 * @return
	 */
	public Object2IntOpenHashMap<ExtensionInformationLevel> getInfiniteInformationAt(int pos)
	{return this.infiniteData[pos];}
	/**
	 * 
	 * @param pos
	 * @param to
	 */
	public void reduceFiniteInformation(int pos, HashSet<ExtensionInformationLevel> to)
	{this.finiteData[pos].keySet().retainAll(to);}
	/**
	 * 
	 * @param pos
	 * @param to
	 */
	public void reduceInfiniteInformation(int pos, HashSet<ExtensionInformationLevel> to)
	{this.infiniteData[pos].keySet().retainAll(to);}
	/**
	 * 
	 * @param i
	 * @param exten
	 */
	public void removeInfiniteInformation(int i, ExtensionInformationLevel exten)
	{this.infiniteData[i].removeInt(exten);}
}